home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
doom
/
chaserog.zip
/
SRC_ROG.ZIP
/
hook.qc
< prev
next >
Wrap
Text File
|
1997-05-02
|
15KB
|
510 lines
//====================================================================
//
// SWINGING GRAPPLING HOOK by: Perecli Manole AKA Bort
//
//====================================================================
// Aside from this new file, the following are the modifications
// done to id's original source files:
//--------------------------------------------------------------------
// File: Progs.src
// Location: before the "weapons.qc" line
// Added: hook.qc
//--------------------------------------------------------------------
// File: Client.qc
// Procedure: PlayerPostThink
// Location: before line "W_WeaponFrame ();"
// Added: CheckGrapHook ();
//--------------------------------------------------------------------
// File: World.qc
// Procedure: worldspawn
// Location: after line "precache_model ("progs/s_spike.mdl");"
// Added: precache_model ("progs/sw_hook.mdl");
// precache_model ("progs/chain.mdl");
//--------------------------------------------------------------------
// File: Weapons.qc
// Procedure: W_Precache
// Location: end of procedure
// Added: precache_sound ("shambler/smack.wav");
// precache_sound ("blob/land1.wav");
// precache_sound ("hook/chain1.wav");
// precache_sound ("hook/chain2.wav");
// precache_sound ("hook/retract.wav");
//--------------------------------------------------------------------
// File: Defs.qc
// Declaration group: player only fields
// Location: after line ".float pain_finished;"
// Added: .float hook;
//--------------------------------------------------------------------
/*
Rob;
<hook>.ammo_shells: grading raise/lower
<hook>.ammo_nails: damageable entity flag
*/
void(vector org, vector vel, float damage) SpawnBlood; // prototype
float () crandom; // prototype
// hook bit flags
float HOOK_ON = 1; // set if hook command is active
float HOOK_IN = 2; // set if hook has attached
float SHRINK_ON = 4; // set if shrink chain is active
float GROW_ON = 8; // set if grow chain is active
// impulse constants
float I_HOOK = 98;
float I_GROW = 97;
float I_SHRINK = 96;
float I_STOP = 95;
// constants
float MIN_CHAIN_LEN = 40; // minimum chain length
float MAX_CHAIN_LEN = 1000; // maximum chain length
float CHAIN_LINK_LEN = 55; // length between chain link origins
//--------------------------------------------------------------------
// Vector dot product function
//--------------------------------------------------------------------
float (vector from, vector onto) Dot =
{
return from_x * onto_x + from_y * onto_y + from_z * onto_z;
};
//--------------------------------------------------------------------
// Removes hook and detaches player
//--------------------------------------------------------------------
void () DropHook =
{
local entity linkptr, nextptr;
// remove all hook flags
self.owner.sw_hook = 0;
sound (self.owner, CHAN_AUTO, "hook/retract.wav", 1, ATTN_NORM);
// removes hook and chain
linkptr = self.goalentity;
while (linkptr != world)
{
nextptr = linkptr.goalentity;
remove (linkptr);
linkptr = nextptr;
}
remove( self );
};
//--------------------------------------------------------------------
// Spawn and removes and refreshes chain links
//--------------------------------------------------------------------
void () MaintainLinks =
{
local vector chainvec, // vector of the chain
p_self_origin, // predicted future hook origin
chainunit; // vector of chain with distance of 1
local entity newlink, // pointer to chain link being added
currlink, // pointer to current link being traversed
nextlink; // pointer to next link after current link
local float chainlen, // length of chain
currpos, // numeric position of currlink
linknum, // number of links that should exist
linkstart; // length from hook at which currlink starts
// predicts hook's future position since chain links fall behind
currpos = vlen(self.velocity) / 22; // currpos used here just as an intermediate value
p_self_origin = self.origin + normalize(self.velocity) * currpos;
// get info about chain
// Rob; put 8 units back for appearances in cam view
if ( (self.dest2_x & CHSCAM_ON) )
{
makevectors( self.owner.v_angle );
chainvec = (((self.owner.origin + '0 0 16') - v_forward * 8) - p_self_origin);
}
else
chainvec = ((self.owner.origin + '0 0 16') - p_self_origin);
chainunit = normalize(chainvec);
chainvec = chainvec - chainunit * 18;
chainlen = vlen(chainvec);
currlink = self;
currpos = 0;
// generate and refresh links
linknum = ceil(chainlen / CHAIN_LINK_LEN);
while (currpos < linknum)
{
// add entities if chain's length grows
if (currlink.goalentity == world)
{
newlink = spawn();
newlink.movetype = MOVETYPE_NOCLIP;
newlink.solid = SOLID_NOT;
setmodel (newlink, "progs/chain.mdl");
setsize (newlink, '0 0 0', '0 0 0');
newlink.goalentity = world;
currlink.goalentity = newlink;
}
currlink = currlink.goalentity;
currpos = currpos + 1;
// set angles
currlink.angles = vectoangles(chainvec);
// fixes vectoangles round off error
if ((currlink.angles_y > 0) && (currlink.angles_y < 180))
currlink.angles = currlink.angles + '0 1 0';
// vibrates chain links on the z axis
currlink.angles_z = currlink.angles_z + crandom() * 30;
// set position and frames
linkstart = (currpos - 1) * CHAIN_LINK_LEN;
if (currpos < linknum)
{
setorigin (currlink, p_self_origin + chainunit * (linkstart + CHAIN_LINK_LEN / 2 ));
currlink.frame = 9;
}
else
{
setorigin (currlink, p_self_origin + chainunit * (linkstart + (chainlen - linkstart) / 2 ));
currlink.frame = floor((chainlen - linkstart) / CHAIN_LINK_LEN * 10);
}
}
// remove remaining entities if chain's length shrinks
nextlink = currlink.goalentity;
currlink.goalentity = world;
currlink = nextlink;
while (currlink != world)
{
nextlink = currlink.goalentity;
remove (currlink);
currlink = nextlink;
}
};
//--------------------------------------------------------------------
// Hook behavior function
//--------------------------------------------------------------------
float GROW_RATE = 16;
float SHRINK_RATE = -20;
void () HookBehavior =
{
local vector spray; // for blood
local vector chainvec; // chain vector
local vector velpart; // player's velocity component moving to or away from hook
local float chainlen; // length of extended chain
//local float framestep; // grow or shrink step per frame
local float f1, f2; // restrainment forces
local float i1, i2; // intermediate values
local float gs; // Rob
self.nextthink = time + 0.01;
// decide when to disconnect hook
if ( !(self.owner.sw_hook & HOOK_ON) || // if hook has been retracted
self.owner.teleport_time > time || // if player goes through teleport
self.owner.solid == SOLID_NOT || // if player dies
self.enemy.solid == SOLID_NOT ) // if target dies
{
DropHook();
return;
}
// give some damage to entities that take damage
if (self.enemy.takedamage)
{
if (time > self.wait)
{
T_Damage (self.enemy, self, self.owner, 5);
// when hook hits live entity add blood and sounds
if (self.enemy.solid == SOLID_SLIDEBOX)
{
// .ammo_nails flag used only here
if (! self.ammo_nails)
{
sound (self, CHAN_AUTO, "shambler/smack.wav", 1, ATTN_NORM);
self.ammo_nails = TRUE;
}
else
sound (self, CHAN_AUTO, "blob/land1.wav", 0.8, ATTN_NORM);
spray_x = 100 * crandom();
spray_y = 100 * crandom();
spray_z = 100 * crandom() + 50;
SpawnBlood (self.origin, spray, 20);
setorigin (self, self.enemy.origin + self.enemy.mins + self.enemy.size * 0.5);
}
self.wait = time + 0.3;
}
}
self.velocity = self.enemy.velocity;
chainvec = self.origin - (self.owner.origin + '0 0 16');
chainlen = vlen (chainvec);
// .ammo_shells = +- amount to size
gs = self.ammo_shells;
////////////////////////////////////////////////
if ( (self.owner.sw_hook & GROW_ON) )
{ gs = gs + 2;
if (gs > GROW_RATE) gs = GROW_RATE;
}
else if ( (self.owner.sw_hook & SHRINK_ON) )
{ gs = gs - 4;
if (gs < SHRINK_RATE) gs = SHRINK_RATE;
}
else
{
if (gs > 0)
{ gs = gs - 2; // fade from grow
if (gs < 0) gs = 0;
}
if (gs < 0)
{ gs = gs + 4; // fade from shrink
if (gs > 0) gs = 0;
}
}
self.armorvalue = self.armorvalue + gs;
if (gs > 0)
{
if ( (self.owner.flags & FL_ONGROUND) )
self.armorvalue = chainlen;
else
{
if (self.delay < time)
{
f1 = gs / GROW_RATE;
sound (self.owner, CHAN_AUTO, "hook/chain1.wav", f1, ATTN_NORM);
self.delay = time + 0.2;
}
}
if ( self.armorvalue > MAX_CHAIN_LEN )
self.armorvalue = MAX_CHAIN_LEN;
}
if (gs < 0)
{
// fixes not raising when directly under the hook
if ( (self.owner.flags & FL_ONGROUND) )
self.owner.flags = self.owner.flags - FL_ONGROUND;
if (self.armorvalue < MIN_CHAIN_LEN)
self.armorvalue = MIN_CHAIN_LEN;
else
{
if (self.delay < time)
{
i1 = fabs(gs);
i2 = fabs(SHRINK_RATE);
f1 = i1 / i2;
sound (self.owner, CHAN_AUTO, "hook/chain2.wav", f1, ATTN_NORM);
self.delay = time + 0.2;
}
}
}
///////////////////////////////////////////////
self.ammo_shells = gs;
// chain physics
// if player's location is beyond the chain's reach
if (chainlen > self.armorvalue)
{
// determine player's velocity component of chain vector
i1 = Dot(self.owner.velocity,chainvec);
i2 = Dot(chainvec,chainvec);
velpart = chainvec * (i1 / i2);
// restrainment default force
f2 = (chainlen - self.armorvalue) * 5;
// if player's velocity heading is away from the hook
if (Dot(self.owner.velocity,chainvec) < 0)
{
if (chainlen > self.armorvalue)
{
self.owner.velocity = self.owner.velocity - (velpart * 0.4);
}
// if chain has streched for 25 units
//if (chainlen > self.armorvalue + 25)
// remove player's velocity component moving away from hook
// self.owner.velocity = self.owner.velocity - velpart;
f1 = f2;
}
else // if player's velocity heading is towards the hook
{
if (vlen(velpart) < f2)
f1 = f2 - vlen(velpart);
else
f1 = 0;
}
}
else
f1 = 0;
// applys chain restrainment
self.owner.velocity = self.owner.velocity + normalize(chainvec) * f1;
MaintainLinks ();
};
//--------------------------------------------------------------------
// Hook's touch function
//--------------------------------------------------------------------
void() HookTouch =
{
// armorvalue is used to hold current length of chain
self.armorvalue = vlen(self.origin - (self.owner.origin + '0 0 16'));
// flags hook as being attached to something
self.owner.sw_hook = self.owner.sw_hook | HOOK_IN;
if (other.solid != SOLID_SLIDEBOX)
{
sound (self, CHAN_AUTO, "player/axhit2.wav", 1, ATTN_NORM);
self.avelocity = '0 0 0';
}
self.velocity = other.velocity;
self.enemy = other;
self.think = HookBehavior;
self.nextthink = time + 0.01;
self.touch = SUB_Null;
};
//--------------------------------------------------------------------
// Limit hook length during launch
//--------------------------------------------------------------------
void() LaunchHook =
{
// armorvalue is used to hold current length of chain
self.armorvalue = vlen(self.origin - (self.owner.origin + '0 0 16'));
if ( !(self.owner.sw_hook & HOOK_ON) ||
self.armorvalue > MAX_CHAIN_LEN ||
self.owner.solid == SOLID_NOT )
{
DropHook();
return;
}
MaintainLinks ();
self.nextthink = time + 0.01;
};
//--------------------------------------------------------------------
// Initiates the hook
//--------------------------------------------------------------------
void(entity myself) InitiateHook =
{
local entity newhook;
newhook = spawn ();
newhook.owner = myself;
newhook.movetype = MOVETYPE_FLY;
newhook.solid = SOLID_BBOX;
setmodel (newhook, "progs/sw_hook.mdl");
setsize (newhook, '0 0 0', '0 0 0');
makevectors (myself.v_angle);
setorigin (newhook, myself.origin + (v_forward*16) + '0 0 16' );
newhook.velocity = v_forward*2000;
newhook.angles = vectoangles(v_forward);
newhook.avelocity = '0 0 600';
sound (myself, CHAN_AUTO, "weapons/ax1.wav", 1, ATTN_NORM);
// used as pointer to first chain link
newhook.goalentity = world;
// Rob; (reminders 0 init values used)
// self.wait = 0; // damage to ents wait cycle
// self.ammo_shells = 0; // graded shrink/grow variable
// self.ammo_nails = FALSE; // initial hit flag for live ents
// self.delay = 0; // wait cycle for chain raising/lowering sounds
newhook.touch = HookTouch;
newhook.nextthink = time + 0.01 ;
newhook.think = LaunchHook;
};
// called by player jump events (weapons.qc: W_WeaponFrame() )
void() CheckGrapHookJump =
{
if ( (self.sw_hook & HOOK_IN) )
{
if ( (self.flags & FL_JUMPRELEASED) && // previous jump cycle has finished
!(self.flags & FL_ONGROUND) ) // player not on ground
{
self.sw_hook = 0; // let hook entity's next think know it's dead
self.velocity_z = self.velocity_z + 200;
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
}
}
};
//--------------------------------------------------------------------
// Checks impulse
//--------------------------------------------------------------------
void() CheckGrapHook =
{
if ((!(self.sw_hook & HOOK_ON)) && (self.impulse == I_HOOK))
{
// flags hook as being active
self.sw_hook = HOOK_ON;
InitiateHook (self);
return;
}
if (self.sw_hook & HOOK_ON)
{
// release hook
if (self.impulse == I_HOOK)
{
self.sw_hook = self.sw_hook - (self.sw_hook & HOOK_ON);
return;
}
// deactivate chain growth or shrink
if (self.impulse == I_STOP)
{
self.sw_hook = self.sw_hook - (self.sw_hook & (GROW_ON | SHRINK_ON));
return;
}
// activate chain growth
if (self.impulse == I_GROW)
{
self.sw_hook = self.sw_hook | GROW_ON;
self.sw_hook = self.sw_hook - (self.sw_hook & SHRINK_ON);
return;
}
// activate chain shrinking
if (self.impulse == I_SHRINK)
{
self.sw_hook = self.sw_hook | SHRINK_ON;
self.sw_hook = self.sw_hook - (self.sw_hook & GROW_ON);
}
}
};